home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AMIGA-CD 2
/
Amiga-CD - Volume 2.iso
/
neue_programme
/
util
/
blank
/
fracblank
/
source
/
fracblank.c
next >
Wrap
C/C++ Source or Header
|
1995-06-01
|
77KB
|
3,968 lines
/*
** FracBlank - AmigaDOS 2.04 commodities utility screenblanker
**
** Copyright © 1991-1995 by Olaf `Olsen' Barthel
** All Rights Reserved
**
** Cosmic flame fractal code derived from xlock source code
**
** Copyright © 1988-1991 by Patrick J. Naughton.
*/
#include <intuition/intuitionbase.h>
#include <intuition/pointerclass.h>
#include <intuition/sghooks.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <libraries/commodities.h>
#include <libraries/asl.h>
#include <datatypes/pictureclass.h>
#include <graphics/gfxbase.h>
#include <hardware/custom.h>
#include <exec/interrupts.h>
#include <exec/execbase.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <dos/rdargs.h>
#include <clib/commodities_protos.h>
#include <clib/intuition_protos.h>
#include <clib/datatypes_protos.h>
#include <clib/graphics_protos.h>
#include <clib/utility_protos.h>
#include <clib/keymap_protos.h>
#include <clib/icon_protos.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/asl_protos.h>
#include <pragmas/datatypes_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <pragmas/keymap_pragmas.h>
#include <pragmas/icon_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/asl_pragmas.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <dos.h>
#include "gtlayout.h"
// Use a simple address trick instead of the predefined
// address in amiga.lib
#ifndef custom
#define custom (*(struct Custom *)0xDFF000)
#endif // custom
// Command line arguments
enum { ARG_PRIORITY,
ARG_POPKEY,
ARG_POPUP,
ARG_BLANKSCREEN,
ARG_SAVESCREEN,
ARG_FRACTAL,
ARG_COLOUR,
ARG_DISPLAYMODE,
ARG_DEPTH,
ARG_SCREENTIMEOUT,
ARG_PATTERNTIMEOUT,
ARG_MAXRECURSION,
ARG_MAXDOTS,
ARGCOUNT
};
// Hotkey IDs
enum { POP_WINDOW,
BLANK_SCREEN,
SAVE_SCREEN
};
// Gadget IDs
enum { GAD_HOTKEY=1000,
GAD_BLANKSCREEN,
GAD_SAVESCREEN,
GAD_MODE,
GAD_HIDE,
GAD_SAVE,
GAD_QUIT
};
// Error codes
enum { ERR_SystemError = 30000, // CBERR_SYSERR
ERR_Duplicate, // CBERR_DUP,
ERR_Version, // CBERR_VERSION,
ERR_BadFilter = 31000, // COERR_BADFILTER,
ERR_BadType, // COERR_BADTYPE
ERR_NoIntuition = 32000, // intuition.library didn't open
ERR_NoGfx, // graphics.library didn't open
ERR_NoAsl, // asl.library didn't open
ERR_NoCommodities, // commodities.library didn't open
ERR_NoUtility, // utility.library didn't open
ERR_NoIcon, // icon.library didn't open
ERR_ScreenModeRequest, // Couldn't allocate ScreenModeRequester
ERR_NoColours, // Couldn't allocate colour table
ERR_NoPointer, // Couldn't create transparent pointer
ERR_NoControlProcess, // Couldn't create control process
ERR_NoMsgPort, // Couldn't create msgport
ERR_NoWindow, // Couldn't open window
ERR_NoKeymap, // Couldn't open keymap.library
ERR_NoGTLayout, // Couldn't open gtlayout.library
};
// All the rawkey codes we know about
#define RAWKEY_CURSOR_UP 76
#define RAWKEY_CURSOR_DOWN 77
#define RAWKEY_CURSOR_RIGHT 78
#define RAWKEY_CURSOR_LEFT 79
#define RAWKEY_F1 80
#define RAWKEY_F2 81
#define RAWKEY_F3 82
#define RAWKEY_F4 83
#define RAWKEY_F5 84
#define RAWKEY_F6 85
#define RAWKEY_F7 86
#define RAWKEY_F8 87
#define RAWKEY_F9 88
#define RAWKEY_F10 89
#define RAWKEY_HELP 95
// Some useful signals
#define SIG_FINISH SIGBREAKF_CTRL_E
#define SIG_BREAK SIGBREAKF_CTRL_C
#define SIG_CHANGE SIGBREAKF_CTRL_D
#define SIG_CYCLE SIGBREAKF_CTRL_E
#define SIG_START SIGBREAKF_CTRL_F
#define SIG_REFRESH SIG_START
#define SIG_WAKEUP SIGBREAKF_CTRL_F
#define SIG_HANDSHAKE SIGF_SINGLE
#define SIG_CX (1L << CxPort -> mp_SigBit)
#define SIG_WINDOW (1L << Window -> UserPort -> mp_SigBit)
// Fractal types
enum { FRACTAL_REAL_PLANE,
FRACTAL_COSMIC_FLAME,
FRACTAL_RANDOM
};
// Colour modes
enum { COLOUR_CYCLE,
COLOUR_STATIC
};
// A 96 bit colour entry
typedef struct ColourEntry
{
ULONG Red,
Green,
Blue;
} ColourEntry;
// A table of colour entries, ready for LoadRGB32()
typedef struct ColourTable
{
WORD NumColours,
FirstColour;
ColourEntry Entry[1];
ULONG Terminator;
} ColourTable;
// Spread a byte across a long word
#define SPREAD(v) ((ULONG)(v) << 24 | (ULONG)(v) << 16 | (ULONG)(v) << 8 | (v))
// Program revision tag
UBYTE VersTag[] = "\0$VER: FracBlank 2.3 (9.3.95)";
// Shared library identifiers
extern struct ExecBase *SysBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *CxBase,
*IconBase,
*AslBase,
*UtilityBase,
*DataTypesBase,
*KeymapBase,
*GTLayoutBase;
// The main program
struct Process *MainProcess;
BOOL PopUp;
// BlankerEntry data
struct SignalSemaphore BlankSemaphore;
struct Hook ScreenHook,
WindowHook;
struct Task *BlankTask;
ULONG CycleMask;
LONG CycleBit;
struct Screen *BlankScreen;
struct Window *BlankWindow;
WORD Width,
Height;
struct RastPort *RPort;
struct ViewPort *VPort;
ULONG Pen;
// A blank pointer
APTR Pointer;
UWORD Nothing;
struct BitMap PointerBitMap;
// String editing hook
struct Hook EditHook;
// BlankerControl data
struct Process *BlankerControlProcess;
// Commodities interface data
struct MsgPort *CxPort;
CxObj *Broker;
ULONG SpecialQualifier;
// Declarations for cosmic flame blanker code
double Flame[2][3][2];
WORD FlameLevel,
FlameAlternateForm;
WORD FlameWheel,
FlameColour;
ULONG FlamePoints;
ULONG MaxRecursionLevel = 40,
MaxFlamePoints = 200;
// Key sequence buffers
UBYTE HotkeyBuffer[256],
BlankScreenBuffer[256],
SaveScreenBuffer[256];
// Screen and pattern change timeout
ULONG ScreenCount = 0,
PatternCount = 0,
ScreenTimeout = 60,
PatternTimeout = 60;
// Some kind of a semaphore to tell the blank task to stop drawing
BYTE StopDrawing = FALSE;
// sin -45° = cos -45° (saves precious calculation time)
double deg45;
// In case we need to rescale things
double VerticalScale;
// The current colour mode
UBYTE ColourMode = COLOUR_CYCLE;
// The current fractal type
UBYTE FractalType = FRACTAL_RANDOM;
// Colour table data
UBYTE Red[255],
Green[255],
Blue[255];
WORD MaxColour,
Wheel;
ColourTable *Colours;
// User interface data
struct Window *Window;
LayoutHandle *Handle;
// Screen mode requester data
struct ScreenModeRequester *ScreenModeRequest;
BOOL ResetRequest = FALSE;
ULONG DisplayID;
WORD DisplayDepth;
WORD Depth;
UBYTE DisplayModeBuffer[DISPLAYNAMELEN + 40];
// The process responsible for saving the screen data to the clipboard
struct Process *Saver;
// A new broker definition, Commodities needs this
struct NewBroker NewBroker =
{
NB_VERSION,
"FracBlank",
"Fractal screen blanker v2.3",
"Screen blanker",
NBU_NOTIFY | NBU_UNIQUE,
COF_SHOW_HIDE,
0,NULL,0
};
// Prototypes for this module
BOOL GetModeName(ULONG Mode,STRPTR Buffer);
struct Library * SafeOpenLibrary(STRPTR Name,LONG Version);
CxObj * CustomHotKey(STRPTR Code,struct MsgPort *Port,LONG ID);
void hsv2rgb(double H,double S,double V,UBYTE *r,UBYTE *g,UBYTE *b);
void hsvramp(double h1,double s1,double b1,double h2,double s2,double b2,int count,UBYTE *red,UBYTE *green,UBYTE *blue);
VOID StuffChar(VOID);
VOID __stdargs SPrintf(STRPTR Buffer,STRPTR FormatString,...);
LONG Atol(STRPTR Buffer);
STRPTR ToolString(STRPTR *Array,STRPTR Match,STRPTR Default);
LONG ToolValue(STRPTR *Array,STRPTR Match,LONG Default);
ULONG BackfillDummy(VOID);
VOID RotatePalette(VOID);
VOID BlackScreen(VOID);
VOID __saveds BlankerControlEntry(VOID);
ULONG Random(ULONG MaxValue);
VOID MonoPlot(WORD Left,WORD Top);
VOID MultiPlot(ULONG Colour,WORD Left,WORD Top);
VOID RealPlane(VOID);
BOOL RecurseMono(double x,double y,WORD Level);
BOOL RecurseColour(double x,double y,WORD Level);
VOID CosmicFlame(VOID);
VOID __saveds BlankerEntry(VOID);
VOID __saveds __stdargs BlankerAction(CxMsg *CxMessage,CxObj *CxObject);
VOID ShutdownCx(VOID);
WORD GetSeconds(STRPTR String);
LONG SetupCx(VOID);
VOID HandleCxMsg(CxMsg *Message);
LONG __saveds __stdargs ShowTime(struct Gadget *SomeGadget,WORD Level);
VOID ShutdownWindow(VOID);
BOOL SetupWindow(VOID);
VOID CloseAll(LONG ReturnCode);
VOID OpenAll(int argc,char **argv);
VOID UpdateModeString(VOID);
VOID SaveOptions(char **argv);
VOID __saveds SaverEntry(VOID);
ULONG BuildMask(STRPTR Code);
ULONG AddQualifier(STRPTR Code,ULONG Qualifier);
ULONG SubQualifier(STRPTR Code,ULONG Qualifier);
WORD __stdargs ShowRequest(struct Window *Window,STRPTR Text,STRPTR Gadgets,...);
VOID ReportError(struct Window *Window,STRPTR Template,LONG Error);
ULONG __saveds __asm EditRoutine(register __a0 struct Hook *Hook,register __a2 struct SGWork *Work,register __a1 ULONG *Msg);
/* EditRoutine():
*
* A special string gadget editing routine for key
* combination input.
*/
ULONG __saveds __asm
EditRoutine(register __a0 struct Hook *Hook,register __a2 struct SGWork *Work,register __a1 ULONG *Msg)
{
struct InputEvent Event;
ULONG Qualifier;
UWORD Code;
UBYTE Key[10];
WORD KeyLen;
STRPTR KeyName;
// If the gadget just got activated or the caps lock key
// is active, don't change anything
if(*Msg == SGH_CLICK || (*Msg == SGH_KEY && (Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CAPSLOCK)))
return(TRUE);
else
{
// Complain if this is not what we expect to be fun
if(*Msg != SGH_KEY)
return(FALSE);
}
// Ditch the qualifier keys
if(Work -> IEvent -> ie_Code >= 96 && Work -> IEvent -> ie_Code <= 103)
{
Work -> Actions &= ~(SGA_USE | SGA_BEEP);
return(TRUE);
}
// Strip all the qualifiers we don't want
Qualifier = Work -> IEvent -> ie_Qualifier & ~(IEQUALIFIER_REPEAT | IEQUALIFIER_INTERRUPT | IEQUALIFIER_MULTIBROADCAST | IEQUALIFIER_RELATIVEMOUSE);
// Check for raw keys
switch(Work -> IEvent -> ie_Code)
{
case RAWKEY_CURSOR_UP:
case RAWKEY_CURSOR_DOWN:
case RAWKEY_CURSOR_RIGHT:
case RAWKEY_CURSOR_LEFT:
// A cursor key was pressed, check if there
// is probably some special feature involved
if(!(Qualifier & ~(IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
return(TRUE);
// FALLS THROUGH TO:
case RAWKEY_F1:
case RAWKEY_F2:
case RAWKEY_F3:
case RAWKEY_F4:
case RAWKEY_F5:
case RAWKEY_F6:
case RAWKEY_F7:
case RAWKEY_F8:
case RAWKEY_F9:
case RAWKEY_F10:
case RAWKEY_HELP:
// Ok, so this is a raw key event
Code = Work -> IEvent -> ie_Code;
KeyLen = 0;
break;
default:
// Make a copy of the inputevent and
// clear the qualifier bits
CopyMem(Work -> IEvent,&Event,sizeof(struct InputEvent));
Event . ie_Qualifier = NULL;
Code = 0;
// Translate the event
if((KeyLen = MapRawKey(&Event,Key,10,NULL)) < 0)
KeyLen = 10;
break;
}
// Is the user holding down a single Amiga key?
if(KeyLen && (Qualifier & IEQUALIFIER_RCOMMAND) && !(Qualifier & ~IEQUALIFIER_RCOMMAND))
{
UBYTE Char = ToUpper(Key[0]);
// Undo and clear are supported
if(Char == 'Q' || Char == 'X')
return(TRUE);
}
// Can we safely continue?
if((!Code && !KeyLen) || KeyLen > 1 || (!Code && KeyLen && !Key[0]))
{
Work -> Actions = (Work -> Actions & ~SGA_USE) | SGA_BEEP;
return(TRUE);
}
// Take care of special characters
if(KeyLen)
{
STATIC struct { UBYTE Code; STRPTR Name; } KeyTable[] =
{
'\r', "Return",
'\b', "Backspace",
'\033', "Escape",
' ', "Spacebar",
',', "Comma",
'\177', "Delete",
'\t', "Tab",
0
};
BOOL GotIt = FALSE;
WORD i;
// Carriage return was pressed
if(Key[0] == '\r')
{
// This probably ends input
if(!Qualifier)
{
Work -> Actions = (Work -> Actions & ~SGA_BEEP) | SGA_USE | SGA_END;
return(TRUE);
}
else
{
// Is this the enter key?
if(Qualifier & IEQUALIFIER_NUMERICPAD)
{
KeyName = "Enter";
Qualifier &= ~IEQUALIFIER_NUMERICPAD;
GotIt = TRUE;
}
}
}
// If this is just the tab key, pass it through cleanly
if(Key[0] == '\t' && !(Qualifier & ~(IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
return(TRUE);
// Now check for special characters
Key[0] = ToUpper(Key[0]);
if(!GotIt)
{
for(i = 0 ; KeyTable[i] . Code ; i++)
{
if(KeyTable[i] . Code == Key[0])
{
KeyName = KeyTable[i] . Name;
GotIt = TRUE;
break;
}
}
}
// If no special character is involved,
// use the vanilla character code
if(!GotIt)
{
if((Key[0] > ' ' && Key[0] < 127) || Key[0] >= 160)
{
Key[1] = 0;
KeyName = Key;
}
else
{
Work -> Actions = (Work -> Actions & ~SGA_USE) | SGA_BEEP;
return(TRUE);
}
}
}
else
{
// Special raw key code table
STATIC struct { UWORD Code; STRPTR Name; } RawTable[] =
{
RAWKEY_CURSOR_UP, "Cursor_Up",
RAWKEY_CURSOR_DOWN, "Cursor_Down",
RAWKEY_CURSOR_RIGHT, "Cursor_Right",
RAWKEY_CURSOR_LEFT, "Cursor_Left",
RAWKEY_F1, "F1",
RAWKEY_F2, "F2",
RAWKEY_F3, "F3",
RAWKEY_F4, "F4",
RAWKEY_F5, "F5",
RAWKEY_F6, "F6",
RAWKEY_F7, "F7",
RAWKEY_F8, "F8",
RAWKEY_F9, "F9",
RAWKEY_F10, "F10",
RAWKEY_HELP, "Help",
0
};
WORD i;
// One eventually must match
for(i = 0 ; RawTable[i] . Code ; i++)
{
if(Code == RawTable[i] . Code)
{
KeyName = RawTable[i] . Name;
break;
}
}
}
// Take care of the qualifiers. Note that we do not distinguish
// between the left and right shift/alt keys
if(Qualifier)
{
STATIC struct { ULONG Qualifier; STRPTR Name; } QualifierTable[] =
{
IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT, "Shift ",
IEQUALIFIER_LALT | IEQUALIFIER_RALT, "Alt ",
IEQUALIFIER_LCOMMAND, "LAmiga ",
IEQUALIFIER_RCOMMAND, "RAmiga ",
IEQUALIFIER_LEFTBUTTON, "Left_Button ",
IEQUALIFIER_MIDBUTTON, "Middle_Button ",
IEQUALIFIER_RBUTTON, "Right_Button ",
IEQUALIFIER_NUMERICPAD, "Numeric_Pad ",
0
};
WORD i;
// Ok, now start building the string
Work -> WorkBuffer[0] = 0;
for(i = 0 ; QualifierTable[i] . Qualifier ; i++)
{
if(Qualifier & QualifierTable[i] . Qualifier)
strcat(Work -> WorkBuffer,QualifierTable[i] . Name);
}
// Add the key itself
strcat(Work -> WorkBuffer,KeyName);
// Update the work data
Work -> NumChars = strlen(Work -> WorkBuffer);
Work -> BufferPos = Work -> NumChars;
// Finished...
Work -> Actions = (Work -> Actions & ~(SGA_BEEP | SGA_PREVACTIVE | SGA_NEXTACTIVE | SGA_END)) | SGA_REDISPLAY | SGA_USE;
}
else
Work -> Actions &= ~(SGA_USE | SGA_BEEP);
return(TRUE);
}
/* ReportError(struct Window *Window,STRPTR Template,LONG Error):
*
* Show an error message.
*/
VOID
ReportError(struct Window *Window,STRPTR Template,LONG Error)
{
STATIC struct { LONG Error; STRPTR Code; } Table[] =
{
ERR_SystemError, "Commodities system error; out of memory",
ERR_Duplicate, "Commodities broker already exists",
ERR_Version, "Commodities broker version not supported",
ERR_BadFilter, "Bad filter descriptor",
ERR_BadType, "Bad type descriptor",
ERR_NoIntuition, "Could not open intuition.library v37",
ERR_NoGfx, "Could not open graphics.library v39",
ERR_NoAsl, "Could not open asl.library v38",
ERR_NoCommodities, "Could not open commodities.library v37",
ERR_NoUtility, "Could not open utility.library v37",
ERR_NoIcon, "Could not open icon.library v37",
ERR_ScreenModeRequest, "Could not allocate screen mode requester",
ERR_NoColours, "Could not allocate colour table; out of memory",
ERR_NoPointer, "Could not allocate mouse pointer; out of memory",
ERR_NoControlProcess, "Could not create mouse blanker process",
ERR_NoMsgPort, "Could not create message port",
ERR_NoWindow, "Could not open window",
ERR_NoKeymap, "Could not open keymap.library",
ERR_NoGTLayout, "Could not open gtlayout.library v9",
0, NULL
};
UBYTE LocalBuffer[256];
STRPTR Buffer;
BOOL GotIt = FALSE;
LONG i;
// Look for the corresponding error message.
for(i = 0 ; Table[i] . Error ; i++)
{
if(Error == Table[i] . Error)
{
Buffer = Table[i] . Code;
GotIt = TRUE;
break;
}
}
if(!GotIt)
{
if(!Fault(Error,"",LocalBuffer,256))
return;
Buffer = &LocalBuffer[2];
}
if(!Template)
Template = Buffer;
if(MainProcess -> pr_CLI && !Window)
{
Printf("FracBlank: ");
Printf(Template,Buffer);
Printf("\n");
}
else
ShowRequest(Window,Template,"Continue",Buffer);
}
/* ShowRequest(struct Window *Window,STRPTR Text,STRPTR Gadgets,...):
*
* This routine shows an easy requester. If there is just one
* button to be pressed, the user will be able to answer it
* by pressing any key.
*/
WORD __stdargs
ShowRequest(struct Window *Window,STRPTR Text,STRPTR Gadgets,...)
{
if(IntuitionBase)
{
struct EasyStruct Easy;
va_list VarArgs;
LONG i,GadgetCount;
for(i = GadgetCount = 0 ; i < strlen(Gadgets) ; i++)
{
if(Gadgets[i] == '|')
GadgetCount++;
}
Easy . es_StructSize = sizeof(struct EasyStruct);
Easy . es_Flags = NULL;
Easy . es_Title = "Fractal screen blanker";
Easy . es_TextFormat = Text;
Easy . es_GadgetFormat = Gadgets;
if(GadgetCount)
{
WORD Result;
if(GTLayoutBase)
LT_LockWindow(Window);
va_start(VarArgs,Gadgets);
Result = EasyRequestArgs(Window,&Easy,NULL,VarArgs);
va_end(VarArgs);
if(GTLayoutBase)
LT_UnlockWindow(Window);
return(Result);
}
else
{
struct Window *ReqWindow;
if(GTLayoutBase)
LT_LockWindow(Window);
va_start(VarArgs,Gadgets);
if(ReqWindow = BuildEasyRequestArgs(Window,&Easy,IDCMP_RAWKEY,VarArgs))
{
ULONG IDCMP;
LONG Result;
FOREVER
{
WaitPort(ReqWindow -> UserPort);
IDCMP = NULL;
Result = SysReqHandler(ReqWindow,&IDCMP,FALSE);
if(!Result || (Result == -2 && !(IDCMP & IDCMP_RAWKEY)))
break;
}
FreeSysRequest(ReqWindow);
}
va_end(VarArgs);
if(GTLayoutBase)
LT_UnlockWindow(Window);
}
}
return(0);
}
/* BuildMask(STRPTR Code):
*
* Build a mask of qualifiers covered by the given
* code.
*/
ULONG
BuildMask(STRPTR Code)
{
IX Expression;
if(!ParseIX(Code,&Expression))
{
ULONG Mask = NULL,Bits = Expression . ix_Qualifier & Expression . ix_QualMask;
// Are shift/caps lock keys involved?
if(Bits & IXSYM_CAPSMASK)
{
// Are both shift keys equivalent?
if(Expression . ix_QualSame & IXSYM_SHIFT)
Mask |= IXSYM_SHIFTMASK | (Bits & IEQUALIFIER_CAPSLOCK);
else
{
// Are all shift/caps lock keys equivalent?
if(Expression . ix_QualSame & IXSYM_CAPS)
Mask |= IXSYM_CAPSMASK;
else
Mask |= Bits & IXSYM_CAPSMASK;
}
}
// Are alt keys involved?
if(Bits & IXSYM_ALTMASK)
{
// Are both alt keys equivalent?
if(Expression . ix_QualSame & IXSYM_ALT)
Mask |= IXSYM_ALTMASK;
else
Mask |= Bits & IXSYM_ALTMASK;
}
// Take care of the remaining qualifiers
Mask |= Bits & ~(IXSYM_ALTMASK | IXSYM_CAPSMASK);
return(Mask);
}
else
return(NULL);
}
/* AddQualifier(STRPTR Code,ULONG Qualifier):
*
* Add to the qualifier mask.
*/
ULONG
AddQualifier(STRPTR Code,ULONG Qualifier)
{
return(Qualifier | BuildMask(Code));
}
/* SubQualifier(STRPTR Code,ULONG Qualifier):
*
* Remove keys from the qualifier mask.
*/
ULONG
SubQualifier(STRPTR Code,ULONG Qualifier)
{
return(Qualifier & ~BuildMask(Code));
}
/* GetModeName(ULONG Mode,STRPTR Buffer):
*
* This routine supplies the name for a DisplayID.
*/
BOOL
GetModeName(ULONG Mode,STRPTR Buffer)
{
struct NameInfo NameInfo;
if(GetDisplayInfoData(NULL,(APTR)&NameInfo,sizeof(struct NameInfo),DTAG_NAME,Mode))
strcpy(Buffer,NameInfo . Name);
else
{
struct DisplayInfo DisplayInfo;
if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode))
{
struct DimensionInfo DimensionInfo;
if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,Mode))
{
STRPTR MonitorName;
switch(Mode & MONITOR_ID_MASK)
{
case NTSC_MONITOR_ID:
MonitorName = "NTSC:";
break;
case PAL_MONITOR_ID:
MonitorName = "PAL:";
break;
case VGA_MONITOR_ID:
MonitorName = "VGA:";
break;
case A2024_MONITOR_ID:
MonitorName = "A2024:";
break;
default:
MonitorName = "";
break;
}
if(DisplayInfo . PropertyFlags & DIPF_IS_HAM)
SPrintf(Buffer,"%s%ld × %ld HAM",MonitorName,DimensionInfo . TxtOScan . MaxX - DimensionInfo . TxtOScan . MinX + 1,DimensionInfo . TxtOScan . MaxY - DimensionInfo . TxtOScan . MinY + 1);
else
SPrintf(Buffer,"%s%ld × %ld",MonitorName,DimensionInfo . TxtOScan . MaxX - DimensionInfo . TxtOScan . MinX + 1,DimensionInfo . TxtOScan . MaxY - DimensionInfo . TxtOScan . MinY + 1);
}
else
return(FALSE);
}
else
return(FALSE);
}
return(TRUE);
}
/* SafeOpenLibrary(STRPTR Name,LONG Version):
*
* Just like OpenLibrary, but makes sure that old
* library versions get flushed from memory.
*/
struct Library *
SafeOpenLibrary(STRPTR Name,LONG Version)
{
struct Library *Base;
Forbid();
if(Base = (struct Library *)FindName(&SysBase -> LibList,FilePart(Name)))
{
if(Base -> lib_Version < Version)
RemLibrary(Base);
}
Permit();
return(OpenLibrary(Name,Version));
}
/* CustomHotKey(STRPTR Code,struct MsgPort *Port,LONG ID):
*
* A replacement for the HotKey() routine found in
* amiga.lib.
*/
CxObj *
CustomHotKey(STRPTR Code,struct MsgPort *Port,LONG ID)
{
CxObj *Filter;
if(Filter = CxFilter(Code))
{
CxObj *Sender;
if(Sender = CxSender(Port,ID))
{
CxObj *Translator;
AttachCxObj(Filter,Sender);
if(Translator = CxTranslate(NULL))
{
AttachCxObj(Filter,Translator);
if(!CxObjError(Filter))
return(Filter);
}
}
DeleteCxObjAll(Filter);
}
return(NULL);
}
/* hsv2rgb(double H,double S,double V,UBYTE *r,UBYTE *g,UBYTE *b):
*
* Convert HSV (hue, saturation, value) colour index into
* plain RGB (red, green, blue) colour space.
*/
void
hsv2rgb(double H,double S,double V,UBYTE *r,UBYTE *g,UBYTE *b)
{
int i;
double f,bb;
UBYTE p,q,t;
H -= floor(H);
H *= 6.0;
i = floor(H);
f = H - (double)i;
bb = 255.0 * V;
p = (UBYTE)(bb * (1.0 - S));
q = (UBYTE)(bb * (1.0 - (S * f)));
t = (UBYTE)(bb * (1.0 - (S * (1.0 - f))));
switch(i)
{
case 0: *r = (UBYTE)bb;
*g = t;
*b = p;
break;
case 1: *r = q;
*g = (UBYTE)bb;
*b = p;
break;
case 2: *r = p;
*g = (UBYTE)bb;
*b = t;
break;
case 3: *r = p;
*g = q;
*b = (UBYTE)bb;
break;
case 4: *r = t;
*g = p;
*b = (UBYTE)bb;
break;
case 5: *r = (UBYTE)bb;
*g = p;
*b = q;
break;
}
}
/* hsvramp():
*
* Creates a ramp within HSV colour space, showing all
* colours of the HSV circle.
*/
void
hsvramp(double h1,double s1,double b1,double h2,double s2,double b2,int count,UBYTE *red,UBYTE *green,UBYTE *blue)
{
double dh,ds,db;
dh = (h2 - h1) / count;
ds = (s2 - s1) / count;
db = (b2 - b1) / count;
while(count--)
{
hsv2rgb(h1,s1,b1,red++,green++,blue++);
h1 += dh;
s1 += ds;
b1 += db;
}
}
VOID
StuffChar()
{
__emit(0x16C0); // MOVE D0,(A3)+
}
/* SPrintf(STRPTR Buffer,STRPTR FormatString,...):
*
* String formatting routine, similar to sprintf().
*/
VOID __stdargs
SPrintf(STRPTR Buffer,STRPTR FormatString,...)
{
va_list VarArgs;
va_start(VarArgs,FormatString);
RawDoFmt(FormatString,VarArgs,(VOID (*)())StuffChar,Buffer);
va_end(VarArgs);
}
/* Atol(STRPTR Buffer):
*
* Convert a string into a long word.
*/
LONG
Atol(STRPTR Buffer)
{
LONG Result;
StrToLong(Buffer,&Result);
return(Result);
}
/* ToolString(STRPTR *Array,STRPTR Match,STRPTR Default):
*
* Return the matching tooltype value, if available.
* Otherwise do with the default value.
*/
STRPTR
ToolString(STRPTR *Array,STRPTR Match,STRPTR Default)
{
if(Array)
{
STRPTR String;
if(String = FindToolType(Array,Match))
return(String);
}
return(Default);
}
/* ToolValue(STRPTR *Array,STRPTR Match,LONG Default):
*
* Return the matching tooltype value, if available.
* Otherwise do with the default value.
*/
LONG
ToolValue(STRPTR *Array,STRPTR Match,LONG Default)
{
if(Array)
{
STRPTR String;
if(String = FindToolType(Array,Match))
{
LONG Result;
if(StrToLong(String,&Result) > 0)
return(Result);
}
}
return(Default);
}
/* BackfillDummy():
*
* A no-op backfill routine, we'll clear the screen manually.
*/
ULONG
BackfillDummy()
{
return(TRUE);
}
/* RotatePalette():
*
* Fill in the screen palette with new data.
*/
VOID
RotatePalette()
{
WORD i,Index = Wheel;
for(i = 1 ; i <= MaxColour ; i++)
{
Colours -> Entry[i] . Red = SPREAD(Red[Index]);
Colours -> Entry[i] . Green = SPREAD(Green[Index]);
Colours -> Entry[i] . Blue = SPREAD(Blue[Index]);
Index = (Index + 1) % MaxColour;
}
// Terminate the table, just in case...
Colours -> Entry[Colours -> NumColours] . Red = 0;
}
/* BlackScreen():
*
* Clear the screen, this is accomplished by first setting the
* screen colours to black, clearing the screen and finally
* restoring the palette.
*/
VOID
BlackScreen()
{
WORD Count;
Count = Colours -> NumColours;
Colours -> NumColours = MaxColour + 1;
memset(&Colours -> Entry[0],0,256 * sizeof(ColourEntry));
LoadRGB32(VPort,(ULONG *)Colours);
SetRast(RPort,0);
Colours -> NumColours = Count;
RotatePalette();
LoadRGB32(VPort,(ULONG *)Colours);
}
/* BlankerControlEntry():
*
* The screen blanker control task.
*/
VOID __saveds
BlankerControlEntry()
{
ULONG SignalSet;
Forbid();
// Ring back...
Signal(MainProcess,SIG_HANDSHAKE);
FOREVER
{
// Wait for something to happen
SignalSet = Wait(SIG_BREAK | SIG_START | SIG_CHANGE | SIG_FINISH);
// Remove both the screen and the blanker task?
if(SignalSet & (SIG_BREAK | SIG_FINISH))
{
ObtainSemaphore(&BlankSemaphore);
if(BlankScreen)
ScreenToBack(BlankScreen);
// Remove the blanker task
if(BlankTask)
{
SetSignal(0,SIG_HANDSHAKE);
// Tell the blanker task to shut down
Signal(BlankTask,SIG_BREAK);
// Move the blanker task priority up,
// we don't want the low priority task
// to wait until some high priority task
// yields CPU time
SetTaskPri(BlankTask,127);
// Wait for handshake signal...
Wait(SIG_HANDSHAKE);
// He's dead, Jim
BlankTask = NULL;
}
// Close the blanker screen
if(BlankScreen)
{
ScreenToBack(BlankScreen);
CloseWindow(BlankWindow);
BlankWindow = NULL;
CloseScreen(BlankScreen);
BlankScreen = NULL;
}
ReleaseSemaphore(&BlankSemaphore);
SignalSet &= ~(SIG_CHANGE | SIG_START);
}
// Leave the town?
if(SignalSet & SIG_FINISH)
break;
// Start the screen blanker?
if(SignalSet & SIG_START)
{
// Is the screen already open?
if(!BlankScreen)
{
ULONG LocalID;
// Use the default public screen display ID
// if necessary
if(DisplayID == INVALID_ID || (ModeNotAvailable(DisplayID) & ~DI_AVAIL_NOTWITHGENLOCK))
{
struct Screen *PubScreen = LockPubScreen(NULL);
if(PubScreen)
{
LocalID = GetVPModeID(&PubScreen -> ViewPort);
UnlockPubScreen(NULL,PubScreen);
}
else
LocalID = INVALID_ID;
}
else
LocalID = DisplayID;
// Did we get a valid ID?
if(LocalID != INVALID_ID)
{
WORD LocalDepth;
struct DimensionInfo DimensionInfo;
struct DisplayInfo DisplayInfo;
// Choose the right display depth
LocalDepth = Depth;
if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(DimensionInfo),DTAG_DIMS,LocalID))
{
if(!LocalDepth)
{
if((LocalDepth = DimensionInfo . MaxDepth) > 8)
LocalDepth = 8;
}
else
{
if(LocalDepth > DimensionInfo . MaxDepth)
LocalDepth = DimensionInfo . MaxDepth;
}
}
else
{
if(!LocalDepth)
LocalDepth = 2;
}
// Compensate for the display aspect ratio
if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(DisplayInfo),DTAG_DISP,LocalID))
{
if(DisplayInfo . Resolution . y)
{
double x,y;
x = (double)DisplayInfo . Resolution . x;
y = (double)DisplayInfo . Resolution . y;
VerticalScale = x / y;
}
else
VerticalScale = 1.0;
}
else
VerticalScale = 1.0;
// Set the colour table to black
MaxColour = (1 << LocalDepth) - 1;
Colours -> NumColours = MaxColour + 1;
memset(&Colours -> Entry[0],0,256 * sizeof(ColourEntry));
// Now open the screen and the window
ObtainSemaphore(&BlankSemaphore);
if(BlankScreen = OpenScreenTags(NULL,
SA_Behind, TRUE,
SA_Quiet, TRUE,
SA_DisplayID, LocalID,
SA_Overscan, OSCAN_MAX,
SA_Depth, LocalDepth,
SA_ShowTitle, FALSE,
SA_BackFill, &ScreenHook,
SA_Colors32, Colours,
SA_Draggable, FALSE,
SA_Exclusive, TRUE,
TAG_DONE))
{
VPort = &BlankScreen -> ViewPort;
Width = BlankScreen -> Width;
Height = BlankScreen -> Height;
// To keep the ball rolling...
if((DisplayDepth = LocalDepth) == 1)
{
MaxColour = 255;
Colours -> NumColours = 2;
}
// Create a nice colour table
hsvramp(0.0,1.0,1.0,1.0,1.0,1.0,MaxColour,Red,Green,Blue);
Wheel = Random(MaxColour);
RotatePalette();
// Open the window
if(BlankWindow = OpenWindowTags(NULL,
WA_Left, 0,
WA_Top, 0,
WA_Width, Width,
WA_Height, Height,
WA_Backdrop, TRUE,
WA_Borderless, TRUE,
WA_Pointer, Pointer,
WA_CustomScreen, BlankScreen,
WA_Activate, TRUE,
WA_RMBTrap, TRUE,
WA_BackFill, &WindowHook,
TAG_DONE))
{
RPort = BlankWindow -> RPort;
SetABPenDrMd(RPort,Pen = 1,0,JAM1);
// Clear the screen
SetRast(RPort,0);
LoadRGB32(VPort,(ULONG *)Colours);
// Display the screen
ScreenToFront(BlankScreen);
PatternCount = 0;
// Wait for something to happen
Forbid();
BlankTask = (struct Task *)CreateTask("« FracBlank BlankerEntry Task »",127,BlankerEntry,4096 + 400 * MaxRecursionLevel);
SetSignal(0,SIG_HANDSHAKE);
Wait(SIG_HANDSHAKE);
Permit();
}
else
{
CloseScreen(BlankScreen);
BlankScreen = NULL;
}
}
}
ReleaseSemaphore(&BlankSemaphore);
}
else
{
// Push the blanker screen to the front if necessary
if(BlankScreen -> TopEdge > 0)
MoveScreen(BlankScreen,0,-BlankScreen -> TopEdge);
if(IntuitionBase -> FirstScreen != BlankScreen)
ScreenToFront(BlankScreen);
if(IntuitionBase -> ActiveWindow != BlankWindow)
ActivateWindow(BlankWindow);
}
SignalSet &= ~SIG_CHANGE;
}
// Change the patterns?
if(SignalSet & SIG_CHANGE)
{
if(BlankTask)
{
// Stop drawing patterns
StopDrawing = TRUE;
Signal(BlankTask,SIG_CHANGE);
}
}
}
BlankerControlProcess = NULL;
Signal(MainProcess,SIG_HANDSHAKE);
}
/* Random(ULONG MaxValue):
*
* Simple random number generation routine.
*/
ULONG
Random(ULONG MaxValue)
{
if(MaxValue)
{
STATIC ULONG RandomSeed = 3735879991;
RandomSeed = RandomSeed * custom . vhposr + 3780343439;
return(RandomSeed % MaxValue);
}
else
return(0);
}
/* MonoPlot(WORD Left,WORD Top):
*
* Set a pixel somewhere on the screen.
*/
VOID
MonoPlot(WORD Left,WORD Top)
{
if(Left >= 0 && Left < Width && Top >= 0 && Top < Height)
WritePixel(RPort,Left,Top);
}
/* MultiPlot(ULONG Colour,WORD Left,WORD Top):
*
* Set a coloured pixel somewhere on the screen.
*/
VOID
MultiPlot(ULONG Colour,WORD Left,WORD Top)
{
if(Left >= 0 && Left < Width && Top >= 0 && Top < Height)
{
if(Pen != Colour)
SetAPen(RPort,Pen = Colour);
WritePixel(RPort,Left,Top);
}
}
/* RealPlane():
*
* Draw real plane fractals.
*/
VOID
RealPlane()
{
UWORD OffsetX = Width / 2,OffsetY = Height / 2;
ULONG Signals;
double x = 0,y = 0,yy,a,b,c,sx,sy,mag;
// Are we running in monochrome mode?
if(DisplayDepth == 1)
{
// Provide starting numbers for the fractal
// parameters
a = (double)(Random(700) + 5) / 100;
b = (double)(Random(190) + 5) / 100;
c = (double)(Random( 90) + 5) / 100;
mag = (double)(1 << (Random(6) + 2)) * deg45;
// Go into fractal generation loop
FOREVER
{
Signals = SetSignal(0,SIG_BREAK | SIG_CHANGE | CycleMask);
// Are we to shut down?
if(Signals & SIG_BREAK)
{
Forbid();
Signal(BlankerControlProcess,SIG_HANDSHAKE);
FreeSignal(CycleBit);
RemTask(NULL);
}
/* The original formula looks like
* this:
* ½
* x = y - SIGN(x) × ABS(b × x - c)
* y = a - x
*
* I have split the calculation into
* several steps to save time and
* variables.
*/
yy = a - x;
if(x < 0)
x = y + sqrt(fabs(b * x - c));
else
x = y - sqrt(fabs(b * x - c));
y = yy;
/* The resulting image appears to have
* been rotated by 45°, so we'll
* rotate the pixel coordinates by -45°
*
* x = x × cos(alpha) + y × sin(alpha)
* y = -x × sin(alpha) + y × cos(alpha)
*
* We also magnify the image (i.e. the
* distribution of pixels) in the following
* lines.
*/
sx = mag * ( x + y);
sy = mag * VerticalScale * (-x + y);
// If the pixel happens to reside within
// the boundaries of the screen, draw it.
MonoPlot((WORD)(sx) + OffsetX,(WORD)(sy) + OffsetY);
// Change the pattern?
if(Signals & SIG_CHANGE)
{
BlackScreen();
StopDrawing = FALSE;
x = y = 0;
a = (double)(Random(700) + 5) / 100;
b = (double)(Random(190) + 5) / 100;
c = (double)(Random( 90) + 5) / 100;
mag = (double)(1 << (Random(6) + 2)) * deg45;
Signals &= ~CycleMask;
}
// Cycle the colours?
if(Signals & CycleMask)
{
LoadRGB32(VPort,(ULONG *)Colours);
Wheel = (Wheel + 1) % MaxColour;
RotatePalette();
}
}
}
else
{
UWORD Count = 0;
WORD Colour;
a = (double)(Random(700) + 5) / 100;
b = (double)(Random(190) + 5) / 100;
c = (double)(Random( 90) + 5) / 100;
mag = (double)(1 << (Random(6) + 2)) * deg45;
Colour = Random(MaxColour - 1) + 1;
FOREVER
{
Signals = SetSignal(0,SIG_BREAK | SIG_CHANGE | CycleMask);
if(Signals & SIG_BREAK)
{
Forbid();
Signal(BlankerControlProcess,SIG_HANDSHAKE);
FreeSignal(CycleBit);
RemTask(NULL);
}
yy = a - x;
if(x < 0)
x = y + sqrt(fabs(b * x - c));
else
x = y - sqrt(fabs(b * x - c));
y = yy;
sx = mag * ( x + y);
sy = mag * VerticalScale * (-x + y);
MultiPlot(Colour,(WORD)(sx) + OffsetX,(WORD)(sy) + OffsetY);
/* Oh well, it's not that easy to
* produce decent colour values for
* the pixels to be rendered.
*
* The following statement will change
* the current drawing pen after exactly
* 1200 pixels have been rendered and will
* pick a new colour between 1 and 31.
*/
if(Count++ >= 1200)
{
WORD NewColour;
Count = 0;
do
NewColour = Random(MaxColour - 1) + 1;
while(NewColour == Colour);
Colour = NewColour;
}
if(Signals & SIG_CHANGE)
{
BlackScreen();
StopDrawing = FALSE;
x = y = 0;
a = (double)(Random(700) + 5) / 100;
b = (double)(Random(190) + 5) / 100;
c = (double)(Random( 90) + 5) / 100;
mag = (double)(1 << (Random(6) + 2)) * deg45;
Signals &= ~CycleMask;
}
if(Signals & CycleMask)
{
LoadRGB32(VPort,(ULONG *)Colours);
Wheel = (Wheel + 1) % MaxColour;
RotatePalette();
}
}
}
}
/* RecurseMono(double x,double y,WORD Level):
*
* Cosmic flame calculation routine (monochrome).
*/
BOOL
RecurseMono(double x,double y,WORD Level)
{
ULONG Signals = SetSignal(0,SIG_BREAK | SIG_CHANGE | CycleMask);
// Are we to shut down?
if(Signals & SIG_BREAK)
{
Forbid();
Signal(BlankerControlProcess,SIG_HANDSHAKE);
FreeSignal(CycleBit);
RemTask(NULL);
}
// Return to top level?
if(StopDrawing)
{
FlameLevel = 0;
StopDrawing = FALSE;
return(FALSE);
}
// Change the pattern?
if(Signals & SIG_CHANGE)
{
FlameLevel = 0;
StopDrawing = FALSE;
return(FALSE);
}
// Cycle the colours?
if(Signals & CycleMask)
{
LoadRGB32(VPort,(ULONG *)Colours);
Wheel = (Wheel + 1) % MaxColour;
RotatePalette();
}
if(Level >= MaxRecursionLevel)
{
if((FlamePoints++) > MaxFlamePoints * 100)
return(FALSE);
else
MonoPlot((WORD)((Width / 2) * (x + 1.0)),(WORD)((Height / 2) * VerticalScale * (y + 1.0)));
}
else
{
double nx,ny;
WORD i;
for(i = 0 ; i < 2 ; i++)
{
nx = Flame[0][0][i] * x + Flame[0][1][i] * y + Flame[0][2][i];
ny = Flame[1][0][i] * x + Flame[1][1][i] * y + Flame[1][2][i];
if(i < FlameAlternateForm)
{
nx = sin(nx);
ny = sin(ny);
}
if(!StopDrawing)
{
if(!RecurseMono(nx,ny,Level + 1))
return(FALSE);
}
else
return(FALSE);
}
}
return(TRUE);
}
/* RecurseColour(double x,double y,WORD Level):
*
* Cosmic flame calculation routine (colour).
*/
BOOL
RecurseColour(double x,double y,WORD Level)
{
ULONG Signals = SetSignal(0,SIG_BREAK | SIG_CHANGE | CycleMask);
if(Signals & SIG_BREAK)
{
Forbid();
Signal(BlankerControlProcess,SIG_HANDSHAKE);
FreeSignal(CycleBit);
RemTask(NULL);
}
if(StopDrawing)
{
FlameLevel = 0;
StopDrawing = FALSE;
return(FALSE);
}
/* Change the pattern? */
if(Signals & SIG_CHANGE)
{
FlameLevel = 0;
StopDrawing = FALSE;
return(FALSE);
}
// Cycle the colours?
if(Signals & CycleMask)
{
LoadRGB32(VPort,(ULONG *)Colours);
Wheel = (Wheel + 1) % MaxColour;
RotatePalette();
}
if(Level >= MaxRecursionLevel)
{
if((FlamePoints++) > MaxFlamePoints * 100)
return(FALSE);
else
MultiPlot(FlameColour,(WORD)((Width / 2) * (x + 1.0)),(WORD)((Height / 2) * VerticalScale * (y + 1.0)));
}
else
{
double nx,ny;
WORD i;
for(i = 0 ; i < 2 ; i++)
{
nx = Flame[0][0][i] * x + Flame[0][1][i] * y + Flame[0][2][i];
ny = Flame[1][0][i] * x + Flame[1][1][i] * y + Flame[1][2][i];
if(i < FlameAlternateForm)
{
nx = sin(nx);
ny = sin(ny);
}
if(!StopDrawing)
{
if(!RecurseColour(nx,ny,Level + 1))
return(FALSE);
}
else
return(FALSE);
}
}
return(TRUE);
}
/* CosmicFlame():
*
* The cosmic flame screen blanker.
*
* xlock.c - X11 client to lock a display and show a screen saver.
*
* Copyright (c) 1988-91 by Patrick J. Naughton.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*/
VOID
CosmicFlame()
{
WORD i,j,k;
BOOL Alternate = FALSE;
FlameLevel = 0;
// Monochrome mode?
if(DisplayDepth == 1)
{
// Go into fractal generation loop
FOREVER
{
if(!((FlameLevel++) % MaxRecursionLevel))
{
BlackScreen();
Alternate = !Alternate;
}
if(Alternate)
FlameAlternateForm = 0;
else
FlameAlternateForm = Random(2) + 2;
for(k = 0 ; k < 2 ; k++)
{
for(i = 0 ; i < 2 ; i++)
{
for(j = 0; j < 3; j++)
Flame[i][j][k] = ((double)Random(1024)) / 512.0 - 1.0;
}
}
FlamePoints = 0;
RecurseMono(0.0,0.0,0);
}
}
else
{
FlameColour = Random(MaxColour - 1) + 1;
FOREVER
{
if(!((FlameLevel++) % MaxRecursionLevel))
{
BlackScreen();
Alternate = !Alternate;
}
else
{
WORD NewColour;
do
NewColour = Random(MaxColour - 1) + 1;
while(NewColour == FlameColour);
FlameColour = NewColour;
}
if(Alternate)
FlameAlternateForm = 0;
else
FlameAlternateForm = Random(2) + 2;
for(k = 0 ; k < 2 ; k++)
{
for(i = 0 ; i < 2 ; i++)
{
for(j = 0; j < 3; j++)
Flame[i][j][k] = ((double)Random(1024)) / 512.0 - 1.0;
}
}
FlamePoints = 0;
RecurseColour(0.0,0.0,0);
}
}
}
/* BlankerEntry():
*
* The screen blanker itself.
*/
VOID __saveds
BlankerEntry()
{
LONG CycleBit;
Forbid();
// Shouldn't go wrong right now, this is the second
// action this task takes, about 16 signal bits
// should still be vacant
if((CycleBit = AllocSignal(-1)) != -1)
{
CycleMask = (1L << CycleBit);
// Tell the control process we're running
Signal(BlankerControlProcess,SIG_HANDSHAKE);
// Now step back
SetTaskPri(SysBase -> ThisTask,-20);
Permit();
// Determine the fractal type
if(FractalType == FRACTAL_COSMIC_FLAME)
CosmicFlame();
else
{
if(FractalType == FRACTAL_REAL_PLANE)
RealPlane();
else
{
if(Random(42) >= 21)
CosmicFlame();
else
RealPlane();
}
}
}
else
{
// Wave goodbye
BlankTask = NULL;
Signal(BlankerControlProcess,SIG_HANDSHAKE);
}
}
/* BlankerAction(CxMsg *CxMessage,CxObj *CxObject):
*
* Commodities support routine, handles the Commodities
* custom actions (in this case: filter the InputEvents
* coming in and enable/disable the screen blanker).
*/
VOID __saveds __stdargs
BlankerAction(CxMsg *CxMessage,CxObj *CxObject)
{
STATIC BYTE Count = 0;
struct InputEvent *Event = (struct InputEvent *)CxMsgData(CxMessage);
// Push the blanker screen to the front if necessary
ObtainSemaphoreShared(&BlankSemaphore);
if(BlankScreen)
Signal(BlankerControlProcess,SIG_REFRESH);
ReleaseSemaphore(&BlankSemaphore);
// This looks like a timer event
if(Event -> ie_Class == IECLASS_TIMER)
{
if(!Window)
{
// Screen blanker still inactive?
ObtainSemaphoreShared(&BlankSemaphore);
if(!BlankTask)
{
// Is there a timeout to take care of?
if(ScreenTimeout && !Window)
{
// Are we ready to create the
// screenblanker?
if(ScreenCount++ >= ScreenTimeout * 10)
Signal(BlankerControlProcess,SIG_START);
}
}
else
{
// Every 5/10 second we signal the blanker
// task to rotate the palette.
if(ColourMode == COLOUR_CYCLE)
{
if(Count++ >= 2)
{
Signal(BlankTask,CycleMask);
Count = 0;
}
}
// Is it time to change the pattern?
if(PatternTimeout)
{
if(PatternCount++ >= PatternTimeout * 10)
{
Signal(BlankerControlProcess,SIG_CHANGE);
PatternCount = 0;
}
}
}
ReleaseSemaphore(&BlankSemaphore);
}
}
else
{
// The following lines determine whether
// the blanker is to be removed or to
// be left running.
switch(Event -> ie_Class)
{
case IECLASS_RAWKEY:
if(!(Event -> ie_Code & IECODE_UP_PREFIX) && !(Event -> ie_Qualifier & SpecialQualifier))
Signal(BlankerControlProcess,SIG_BREAK);
break;
case IECLASS_NEWPOINTERPOS:
case IECLASS_POINTERPOS:
case IECLASS_RAWMOUSE:
Signal(BlankerControlProcess,SIG_BREAK);
break;
}
ScreenCount = 0;
}
}
/* ShutdownCx():
*
* Close the Commodities interface.
*/
VOID
ShutdownCx()
{
if(CxPort)
{
struct Message *Message;
// Remove the broker
if(Broker)
DeleteCxObjAll(Broker);
// Remove the MsgPort from the public list
RemPort(CxPort);
// Remove all pending messages
while(Message = GetMsg(CxPort))
ReplyMsg(Message);
// Delete the MsgPort
DeleteMsgPort(CxPort);
CxPort = NULL;
Broker = NULL;
}
}
/* GetSeconds(STRPTR String):
*
* Calculates the number of seconds corresponding to
* expressions such as `11:25' or `10'.
*/
WORD
GetSeconds(STRPTR String)
{
UBYTE Buffer[10];
WORD i,Seconds;
CopyMem(String,Buffer,9);
Buffer[9] = 0;
String = Buffer;
for(i = strlen(String) - 1 ; i >= 0 ; i--)
{
if(String[i] == ':')
{
Seconds = Atol(&String[i + 1]);
String[i] = 0;
Seconds += 60 * Atol(String);
if(Seconds > 30 * 60)
Seconds = 30 * 60;
return(Seconds);
}
}
if((Seconds = Atol(String)) > 30 * 60)
Seconds = 30 * 60;
return(Seconds);
}
/* SetupCx():
*
* Set up the Commodities interface.
*/
LONG
SetupCx()
{
LONG Error;
// Cancel any previously made assignments
ShutdownCx();
// Create a reply port
if(CxPort = CreateMsgPort())
{
// Fill in a unique name
CxPort -> mp_Node . ln_Name = NewBroker . nb_Name;
// Add the reply port to the public list
AddPort(CxPort);
// Install the replyport
NewBroker . nb_Port = CxPort;
// Create the broker
if(Broker = CxBroker(&NewBroker,&Error))
{
CxObj *ObjectList;
// Link the hotkeys
AttachCxObj(Broker,CustomHotKey(HotkeyBuffer, CxPort,POP_WINDOW));
AttachCxObj(Broker,CustomHotKey(BlankScreenBuffer, CxPort,BLANK_SCREEN));
AttachCxObj(Broker,CustomHotKey(SaveScreenBuffer, CxPort,SAVE_SCREEN));
// Install the plain InputEvent handler
ObjectList = CxCustom(BlankerAction,NULL);
// Any accumulated errors?
if(!(Error = CxObjError(ObjectList)))
{
// Add the custom object
AttachCxObj(Broker,ObjectList);
// Any errors?
if(!(Error = CxObjError(Broker)))
{
// Activate the broker
ActivateCxObj(Broker,TRUE);
return(0);
}
}
if(Error & COERR_BADFILTER)
Error = ERR_BadFilter;
else
{
if(Error & COERR_BADTYPE)
Error = ERR_BadType;
else
Error = ERROR_NO_FREE_STORE;
}
}
else
Error = Error - CBERR_SYSERR + ERR_SystemError;
}
else
Error = ERR_NoMsgPort;
ShutdownCx();
return(Error);
}
/* SaverEntry():
*
* This background process handles the job of storing the
* contents of the screen in the clipboard.
*/
VOID __saveds
SaverEntry()
{
struct BitMap *BitMap;
// That's me
Saver = (struct Process *)FindTask(NULL);
ObtainSemaphoreShared(&BlankSemaphore);
Forbid();
// Create a bitmap to hold a copy of the screen
if(BitMap = AllocBitMap(Width,Height,DisplayDepth,NULL,RPort -> BitMap))
{
STATIC ULONG Count = 1;
UBYTE LocalBuffer[256];
Object *Image;
// Copy the contents
BltBitMap(RPort -> BitMap,0,0,BitMap,0,0,Width,Height,0xC0,(1L << DisplayDepth) - 1,NULL);
// Wait until they have arrived
WaitBlit();
Permit();
ReleaseSemaphore(&BlankSemaphore);
// Build a unique name, in case someone needs it
SPrintf(LocalBuffer,"FracBlank_%ld×%ld×%ld_%ld",Width,Height,DisplayDepth,Count++);
// Wrap the bitmap into an image object
if(Image = NewDTObject(LocalBuffer,
DTA_SourceType, DTST_RAM,
DTA_GroupID, GID_PICTURE,
PDTA_NumColors, 1L << DisplayDepth,
PDTA_BitMap, BitMap,
PDTA_ModeID, GetVPModeID(&BlankScreen -> ViewPort),
TAG_DONE))
{
struct ColorRegister *ColourMap;
struct BitMapHeader *BitMapHeader;
ULONG *ColourTab;
// Get the internal data storage pointers
if(GetDTAttrs(Image,
PDTA_BitMapHeader, &BitMapHeader,
PDTA_ColorRegisters, &ColourMap,
PDTA_CRegs, &ColourTab,
TAG_DONE) == 3)
{
LONG i;
// Fill in the header
BitMapHeader -> bmh_Left = 0;
BitMapHeader -> bmh_Top = 0;
BitMapHeader -> bmh_Width = Width;
BitMapHeader -> bmh_Height = Height;
BitMapHeader -> bmh_Depth = DisplayDepth;
BitMapHeader -> bmh_PageWidth = Width;
BitMapHeader -> bmh_PageHeight = Height;
// Fill in the colour tables
for(i = 0 ; i < 1L << DisplayDepth ; i++)
{
ColourTab[i * 3 + 0] = Colours -> Entry[i] . Red;
ColourTab[i * 3 + 1] = Colours -> Entry[i] . Green;
ColourTab[i * 3 + 2] = Colours -> Entry[i] . Blue;
ColourMap[i] . red = Colours -> Entry[i] . Red >> 24;
ColourMap[i] . green = Colours -> Entry[i] . Green >> 24;
ColourMap[i] . blue = Colours -> Entry[i] . Blue >> 24;
}
// Put the image into the clipboard
DoMethod(Image,DTM_COPY,NULL);
}
DisposeDTObject(Image);
}
else
FreeBitMap(BitMap);
}
else
{
Permit();
ReleaseSemaphore(&BlankSemaphore);
}
Forbid();
Saver = NULL;
}
/* HandleCxMsg(CxMsg *Message):
*
* Handle incoming Commodities messages.
*/
VOID
HandleCxMsg(CxMsg *Message)
{
ULONG MessageID = CxMsgID(Message),MessageType = CxMsgType(Message);
ReplyMsg((struct Message *)Message);
// Take a look at the message type
switch(MessageType)
{
// It's a hotkey
case CXM_IEVENT:
switch(MessageID)
{
// Create the control panel
case POP_WINDOW:
// Make sure the blanker has terminated
Signal(BlankerControlProcess,SIG_BREAK);
SetupWindow();
break;
// Blank the screen
case BLANK_SCREEN:
if(!Window)
{
ObtainSemaphoreShared(&BlankSemaphore);
if(!BlankTask)
Signal(BlankerControlProcess,SIG_START);
else
{
Signal(BlankerControlProcess,SIG_CHANGE);
PatternCount = 0;
}
ReleaseSemaphore(&BlankSemaphore);
}
break;
// Save the screen in the clipboard
case SAVE_SCREEN:
if(DataTypesBase)
{
ObtainSemaphoreShared(&BlankSemaphore);
// Let the background process handle the job
if(BlankScreen && !Saver)
{
CreateNewProcTags(
NP_Name, "« FracBlank Screen Saver »",
NP_Entry, SaverEntry,
NP_StackSize, 4096,
NP_WindowPtr, -1,
TAG_DONE);
}
ReleaseSemaphore(&BlankSemaphore);
}
break;
}
break;
// It's an internal Commodities command
case CXM_COMMAND:
switch(MessageID)
{
// Disable the Commodity
case CXCMD_DISABLE:
ActivateCxObj(Broker,FALSE);
break;
// Enable the Commodity
case CXCMD_ENABLE:
ActivateCxObj(Broker,TRUE);
break;
// Create the control panel
case CXCMD_APPEAR:
case CXCMD_UNIQUE:
SetupWindow();
break;
// Close the control panel
case CXCMD_DISAPPEAR:
ShutdownWindow();
break;
// Remove this Commodity
case CXCMD_KILL:
CloseAll(RETURN_OK);
break;
}
break;
}
}
/* ShowTime(struct Gadget *SomeGadget,WORD Level):
*
* Gadtools support routine, displays the timeouts.
*/
LONG __saveds __stdargs
ShowTime(struct Gadget *SomeGadget,WORD Level)
{
STATIC UBYTE Buffer[30];
if(Level)
SPrintf(Buffer,"%2ld:%02ld min.",Level / 60,Level % 60);
else
SPrintf(Buffer,"«Off»");
return((LONG)Buffer);
}
/* ShowDots(struct Gadget *SomeGadget,WORD Level):
*
* Cheap trick; multiply the number of dots by 100.
*/
LONG __saveds __stdargs
ShowDots(struct Gadget *SomeGadget,WORD Level)
{
return((LONG)Level * 100);
}
/* ShutdownWindow():
*
* Closes the control panel.
*/
VOID
ShutdownWindow()
{
if(Handle)
{
LT_DeleteHandle(Handle);
Handle = NULL;
Window = NULL;
CloseLibrary(GTLayoutBase);
GTLayoutBase = NULL;
}
}
/* SetupWindow():
*
* Creates the control panel and disables the screen
* blanker.
*/
BOOL
SetupWindow()
{
if(Handle)
{
LT_ShowWindow(Handle,TRUE);
return(TRUE);
}
else
{
if(!(GTLayoutBase = SafeOpenLibrary("PROGDIR:gtlayout.library",9)))
GTLayoutBase = SafeOpenLibrary("gtlayout.library",9);
if(GTLayoutBase)
{
if(Handle = LT_CreateHandleTagList(NULL,NULL))
{
LT_New(Handle,
LA_Type, VERTICAL_KIND,
TAG_DONE);
{
LT_New(Handle,
LA_LabelText, "Fractal screen blanker",
LA_Type, VERTICAL_KIND,
TAG_DONE);
{
STATIC STRPTR Copyright[] =
{
"Copyright © 1991-1995",
"by Olaf `Olsen' Barthel",
"All Rights Reserved",
NULL
};
LT_New(Handle,
LA_Type, BOX_KIND,
LABX_Lines, Copyright,
LABX_AlignText, ALIGNTEXT_CENTERED,
LA_DrawBox, FALSE,
TAG_DONE);
LT_EndGroup(Handle);
}
LT_New(Handle,
LA_LabelText, "Controls",
LA_Type, VERTICAL_KIND,
TAG_DONE);
{
STATIC STRPTR FractalTypes[] =
{
"Real plane",
"Cosmic flames",
"« Random »",
NULL
};
STATIC STRPTR ColourModes[] =
{
"Cycling",
"Static",
NULL
};
LT_New(Handle,
LA_Type, SLIDER_KIND,
LA_LabelText, "Screen timeout",
GTSL_Min, 0,
GTSL_Max, 30 * 60,
GTSL_LevelFormat, "%s",
GTSL_DispFunc, ShowTime,
LA_ULONG, &ScreenTimeout,
LA_Chars, 20,
TAG_DONE);
LT_New(Handle,
LA_Type, SLIDER_KIND,
LA_LabelText, "Pattern timeout",
GTSL_Min, 0,
GTSL_Max, 30 * 60,
GTSL_LevelFormat, "%s",
GTSL_DispFunc, ShowTime,
LA_ULONG, &PatternTimeout,
TAG_DONE);
LT_New(Handle,
LA_Type, XBAR_KIND,
TAG_DONE);
EditHook . h_Entry = (HOOKFUNC)EditRoutine;
LT_New(Handle,
LA_Type, STRING_KIND,
LA_LabelText, "Hot key",
GTST_MaxChars, 255,
GTST_String, HotkeyBuffer,
GTST_EditHook, &EditHook,
LA_ID, GAD_HOTKEY,
TAG_DONE);
LT_New(Handle,
LA_Type, STRING_KIND,
LA_LabelText, "Blank screen",
GTST_MaxChars, 255,
GTST_String, BlankScreenBuffer,
GTST_EditHook, &EditHook,
LA_ID, GAD_BLANKSCREEN,
TAG_DONE);
if(DataTypesBase)
{
LT_New(Handle,
LA_Type, STRING_KIND,
LA_LabelText, "Save screen to clipboard",
GTST_MaxChars, 255,
GTST_String, SaveScreenBuffer,
GTST_EditHook, &EditHook,
LA_ID, GAD_SAVESCREEN,
TAG_DONE);
}
LT_New(Handle,
LA_Type, XBAR_KIND,
TAG_DONE);
UpdateModeString();
LT_New(Handle,
LA_Type, TEXT_KIND,
LA_LabelText, "Display mode",
LA_ID, GAD_MODE,
GTTX_Text, DisplayModeBuffer,
GTTX_Border, TRUE,
LATX_Picker, TRUE,
TAG_DONE);
LT_New(Handle,
LA_Type, XBAR_KIND,
TAG_DONE);
LT_New(Handle,
LA_Type, CYCLE_KIND,
LA_LabelText, "Colour mode",
GTCY_Labels, ColourModes,
LA_UBYTE, &ColourMode,
TAG_DONE);
LT_New(Handle,
LA_Type, CYCLE_KIND,
LA_LabelText, "Fractal type",
GTCY_Labels, FractalTypes,
LA_UBYTE, &FractalType,
TAG_DONE);
LT_New(Handle,
LA_Type, SLIDER_KIND,
LA_LabelText, "Maximum recursion level",
GTSL_Min, 10,
GTSL_Max, 100,
GTSL_LevelFormat, "%ld",
LA_ULONG, &MaxRecursionLevel,
TAG_DONE);
LT_New(Handle,
LA_Type, SLIDER_KIND,
LA_LabelText, "Maximum dots",
GTSL_Min, 10,
GTSL_Max, 1000,
GTSL_LevelFormat, "%lD",
GTSL_DispFunc, ShowDots,
LA_ULONG, &MaxFlamePoints,
TAG_DONE);
LT_EndGroup(Handle);
}
LT_New(Handle,
LA_Type, VERTICAL_KIND,
TAG_DONE);
{
LT_New(Handle,
LA_Type, XBAR_KIND,
LAXB_FullSize, TRUE,
TAG_DONE);
LT_EndGroup(Handle);
}
LT_New(Handle,
LA_Type, HORIZONTAL_KIND,
LAGR_Spread, TRUE,
LAGR_SameSize, TRUE,
TAG_DONE);
{
if(!MainProcess -> pr_CLI)
{
LT_New(Handle,
LA_Type, BUTTON_KIND,
LA_LabelText, "Save",
LABT_ExtraFat, TRUE,
LA_ID, GAD_SAVE,
LA_Chars, 8,
TAG_DONE);
}
LT_New(Handle,
LA_Type, BUTTON_KIND,
LA_LabelText, "Hide",
LABT_ReturnKey, TRUE,
LABT_ExtraFat, TRUE,
LA_ID, GAD_HIDE,
LA_Chars, 8,
TAG_DONE);
LT_New(Handle,
LA_Type, BUTTON_KIND,
LA_LabelText, "Quit",
LA_ID, GAD_QUIT,
TAG_DONE);
LT_EndGroup(Handle);
}
LT_EndGroup(Handle);
}
if(Window = LT_Build(Handle,
LAWN_IDCMP, IDCMP_CLOSEWINDOW,
LAWN_BelowMouse, TRUE,
LAWN_SmartZoom, TRUE,
LAWN_TitleText, &VersTag[7],
WA_DepthGadget, TRUE,
WA_CloseGadget, TRUE,
WA_DragBar, TRUE,
WA_RMBTrap, TRUE,
WA_Activate, TRUE,
TAG_DONE))
{
ResetRequest = TRUE;
return(TRUE);
}
LT_DeleteHandle(Handle);
Handle = NULL;
}
ReportError(NULL,NULL,ERR_NoWindow);
CloseLibrary(GTLayoutBase);
GTLayoutBase = NULL;
}
else
ReportError(NULL,NULL,ERR_NoGTLayout);
return(FALSE);
}
}
/* CloseAll(LONG ReturnCode):
*
* Free all resources and exit the program.
*/
VOID
CloseAll(LONG ReturnCode)
{
// Wait until the screen is saved
while(Saver)
Delay(TICKS_PER_SECOND);
if(CxBase)
ShutdownCx();
if(BlankerControlProcess)
{
Forbid();
SetSignal(0,SIG_HANDSHAKE);
Signal(BlankerControlProcess,SIG_FINISH);
Wait(SIG_HANDSHAKE);
Permit();
}
if(Pointer)
DisposeObject(Pointer);
ShutdownWindow();
if(Colours)
FreeVec(Colours);
if(ScreenModeRequest)
FreeAslRequest(ScreenModeRequest);
if(KeymapBase)
CloseLibrary(KeymapBase);
if(IconBase)
CloseLibrary(IconBase);
if(UtilityBase)
CloseLibrary(UtilityBase);
if(CxBase)
CloseLibrary(CxBase);
if(AslBase)
CloseLibrary(AslBase);
if(DataTypesBase)
CloseLibrary(DataTypesBase);
if(GfxBase)
CloseLibrary(GfxBase);
if(IntuitionBase)
CloseLibrary(IntuitionBase);
exit(ReturnCode);
}
/* OpenAll(int argc,char **argv):
*
* Open all resources, initialize the colour table and
* create the Commodities interface.
*/
VOID
OpenAll(int argc,char **argv)
{
STRPTR *ToolTypes,
String,
Array[ARGCOUNT];
struct RDArgs *Args;
struct DiskObject *Icon;
IX Expression;
LONG Error;
// Initialize this, the rotation code needs it
deg45 = sin(-45.0);
ScreenHook . h_Entry = (HOOKFUNC)BackfillDummy;
WindowHook . h_Entry = (HOOKFUNC)BackfillDummy;
InitSemaphore(&BlankSemaphore);
MainProcess = (struct Process *)FindTask(NULL);
// Open the libraries we need
if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37)))
CloseAll(RETURN_FAIL);
if(!(CxBase = OpenLibrary("commodities.library",37)))
{
ReportError(NULL,NULL,ERR_NoCommodities);
CloseAll(RETURN_FAIL);
}
if(!(UtilityBase = OpenLibrary("utility.library",37)))
{
ReportError(NULL,NULL,ERR_NoUtility);
CloseAll(RETURN_FAIL);
}
if(!(IconBase = OpenLibrary("icon.library",0)))
{
ReportError(NULL,NULL,ERR_NoIcon);
CloseAll(RETURN_FAIL);
}
if(!(AslBase = OpenLibrary("asl.library",38)))
{
ReportError(NULL,NULL,ERR_NoAsl);
CloseAll(RETURN_FAIL);
}
if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",39)))
{
ReportError(NULL,NULL,ERR_NoGfx);
CloseAll(RETURN_FAIL);
}
if(!(KeymapBase = OpenLibrary("keymap.library",37)))
{
ReportError(NULL,NULL,ERR_NoKeymap);
CloseAll(RETURN_FAIL);
}
DataTypesBase = OpenLibrary("datatypes.library",39);
if(!(ScreenModeRequest = AllocAslRequestTags(ASL_ScreenModeRequest,
ASLSM_DoDepth, TRUE,
ASLSM_PropertyFlags, NULL,
ASLSM_PropertyMask, DIPF_IS_DUALPF | DIPF_IS_PF2PRI | DIPF_IS_HAM | DIPF_IS_EXTRAHALFBRITE,
ASLSM_MinDepth, 1,
ASLSM_MaxDepth, 8,
ASLSM_UserData, FALSE,
TAG_DONE)))
{
ReportError(NULL,NULL,ERR_ScreenModeRequest);
CloseAll(RETURN_FAIL);
}
// Set up a transparent window pointer
InitBitMap(&PointerBitMap,2,16,1);
PointerBitMap . Planes[0] = PointerBitMap . Planes[1] = (PLANEPTR)&Nothing;
if(!(Pointer = NewObject(NULL,POINTERCLASS,
POINTERA_BitMap, &PointerBitMap,
POINTERA_XOffset, 0,
POINTERA_YOffset, 0,
POINTERA_WordWidth, 2,
TAG_DONE)))
{
ReportError(NULL,NULL,ERR_NoPointer);
CloseAll(RETURN_FAIL);
}
if(!(Colours = (ColourTable *)AllocVec(sizeof(ColourTable) + 255 * sizeof(ColourEntry),MEMF_ANY | MEMF_PUBLIC | MEMF_CLEAR)))
{
ReportError(NULL,NULL,ERR_NoColours);
CloseAll(RETURN_FAIL);
}
Forbid();
if(BlankerControlProcess = CreateNewProcTags(
NP_Name, "« FracBlank Control Process »",
NP_Priority, 100,
NP_Entry, BlankerControlEntry,
NP_StackSize, 4096,
NP_WindowPtr, -1,
TAG_DONE))
{
SetSignal(0,SIG_HANDSHAKE);
// Wait for handshake signal
Wait(SIG_HANDSHAKE);
}
Permit();
if(!BlankerControlProcess)
{
ReportError(NULL,NULL,ERR_NoControlProcess);
CloseAll(RETURN_FAIL);
}
memset(Array,0,sizeof(Array));
if(argc)
{
if(!(Args = ReadArgs("CX_PRIORITY/N/K,CX_POPKEY/K,CX_POPUP/K,BLANKSCREEN/K,SAVESCREEN/K,FRACTAL/K,COLOUR/K,DISPLAYMODE/K,DEPTH/N/K,SCREENTIMEOUT/K,PATTERNTIMEOUT/K,MAXRECURSION/N/K,MAXDOTS/N/K",(LONG *)Array,NULL)))
{
PrintFault(IoErr(),"FracBlank");
CloseAll(RETURN_FAIL);
}
ToolTypes = NULL;
Icon = NULL;
}
else
{
struct WBStartup *Startup = (struct WBStartup *)argv;
BPTR OldDir;
Args = NULL;
OldDir = CurrentDir(MainProcess -> pr_HomeDir);
if(Icon = GetDiskObject(Startup -> sm_ArgList -> wa_Name))
ToolTypes = (STRPTR *)Icon -> do_ToolTypes;
else
ToolTypes = NULL;
CurrentDir(OldDir);
}
NewBroker . nb_Pri = ToolValue(ToolTypes,"CX_PRIORITY",Array[ARG_PRIORITY] ? *(LONG *)Array[ARG_PRIORITY] : 0);
if(NewBroker . nb_Pri < -128)
NewBroker . nb_Pri = -128;
else
{
if(NewBroker . nb_Pri > 127)
NewBroker . nb_Pri = 127;
}
// We'll put up a mask of qualifiers we don't want the blanker
// to stop at
SpecialQualifier = IEQUALIFIER_REPEAT;
// Set the Commodity popup hotkey if possible
strcpy(HotkeyBuffer,ToolString(ToolTypes,"CX_POPKEY",Array[ARG_POPKEY] ? Array[ARG_POPKEY] : (STRPTR)"shift f1"));
SpecialQualifier = AddQualifier(HotkeyBuffer,SpecialQualifier);
if(Error = ParseIX(HotkeyBuffer,&Expression))
{
ReportError(NULL,"Invalid CX_POPKEY specification\n%s",ERR_BadFilter);
CloseAll(RETURN_FAIL);
}
/* Determine the screen blanker hotkey. */
strcpy(BlankScreenBuffer,ToolString(ToolTypes,"BLANKSCREEN",Array[ARG_BLANKSCREEN] ? Array[ARG_BLANKSCREEN] : (STRPTR)"shift f2"));
SpecialQualifier = AddQualifier(BlankScreenBuffer,SpecialQualifier);
if(Error = ParseIX(BlankScreenBuffer,&Expression))
{
ReportError(NULL,"Invalid BLANKSCREEN specification\n%s",ERR_BadFilter);
CloseAll(RETURN_FAIL);
}
// Set the screen save hotkey
strcpy(SaveScreenBuffer,ToolString(ToolTypes,"SAVESCREEN",Array[ARG_SAVESCREEN] ? Array[ARG_SAVESCREEN] : (STRPTR)"shift f3"));
SpecialQualifier = AddQualifier(SaveScreenBuffer,SpecialQualifier);
if(Error = ParseIX(SaveScreenBuffer,&Expression))
{
ReportError(NULL,"Invalid SAVESCREEN specification\n%s",ERR_BadFilter);
CloseAll(RETURN_FAIL);
}
// Which fractal type?
String = ToolString(ToolTypes,"FRACTAL",Array[ARG_FRACTAL] ? Array[ARG_FRACTAL] : (STRPTR)"RANDOM");
if(MatchToolValue(String,"REALPLANE") || MatchToolValue(String,"REAL"))
FractalType = FRACTAL_REAL_PLANE;
else
{
if(MatchToolValue(String,"COSMICFLAME") || MatchToolValue(String,"COSMIC") || MatchToolValue(String,"FLAME"))
FractalType = FRACTAL_COSMIC_FLAME;
else
FractalType = FRACTAL_RANDOM;
}
// Which colour mode?
String = ToolString(ToolTypes,"COLOUR",Array[ARG_COLOUR] ? Array[ARG_COLOUR] : (STRPTR)"CYCLE");
if(MatchToolValue(String,"STATIC"))
ColourMode = COLOUR_STATIC;
else
ColourMode = COLOUR_CYCLE;
// Which display mode?
DisplayID = INVALID_ID;
if(String = ToolString(ToolTypes,"DISPLAYMODE",Array[ARG_DISPLAYMODE]))
{
UBYTE LocalBuffer[40];
ULONG ID = INVALID_ID;
while((ID = NextDisplayInfo(ID)) != INVALID_ID)
{
if(GetModeName(ID,LocalBuffer))
{
if(!Stricmp(LocalBuffer,String))
{
struct DisplayInfo DisplayInfo;
if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,ID))
{
if(!(DisplayInfo . NotAvailable & ~DI_AVAIL_NOTWITHGENLOCK))
{
if(!(DisplayInfo . PropertyFlags & (DIPF_IS_DUALPF | DIPF_IS_PF2PRI | DIPF_IS_HAM | DIPF_IS_EXTRAHALFBRITE)))
{
DisplayID = ID;
break;
}
}
}
}
}
}
}
// Which depth?
Depth = ToolValue(ToolTypes,"DEPTH",Array[ARG_DEPTH] ? *(LONG *)Array[ARG_DEPTH] : 0);
if(Depth > 8)
Depth = 8;
else
{
if(Depth < 0)
Depth = 0;
}
// Adjust the screen timeout if possible
ScreenTimeout = GetSeconds(ToolString(ToolTypes,"SCREENTIMEOUT",Array[ARG_SCREENTIMEOUT] ? Array[ARG_SCREENTIMEOUT] : (STRPTR)"1:00"));
// Adjust the pattern change timeout
PatternTimeout = GetSeconds(ToolString(ToolTypes,"PATTERNTIMEOUT",Array[ARG_PATTERNTIMEOUT] ? Array[ARG_PATTERNTIMEOUT] : (STRPTR)"1:00"));
// Take care of the recursion level
MaxRecursionLevel = ToolValue(ToolTypes,"MAXRECURSION",Array[ARG_MAXRECURSION] ? *(LONG *)Array[ARG_MAXRECURSION] : 40);
if(MaxRecursionLevel < 10)
MaxRecursionLevel = 10;
else
{
if(MaxRecursionLevel > 100)
MaxRecursionLevel = 100;
}
// Now for the cosmic flame dots
MaxFlamePoints = ToolValue(ToolTypes,"MAXDOTS",Array[ARG_MAXDOTS] ? *(LONG *)Array[ARG_MAXDOTS] : 20000);
MaxFlamePoints /= 100;
if(MaxFlamePoints < 10)
MaxFlamePoints = 10;
else
{
if(MaxFlamePoints > 1000)
MaxFlamePoints = 1000;
}
// Create the commodities interface
if(Error = SetupCx())
{
if(Error != ERR_Duplicate)
ReportError(NULL,NULL,Error);
if(Args)
FreeArgs(Args);
if(Icon)
FreeDiskObject(Icon);
CloseAll(RETURN_FAIL);
}
// Pop up the control panel if necessary
if(MatchToolValue(ToolString(ToolTypes,"CX_POPUP",Array[ARG_POPUP] ? Array[ARG_POPUP] : (STRPTR)"no"),"yes"))
{
PopUp = TRUE;
SetupWindow();
}
// Clean up
if(Args)
FreeArgs(Args);
if(Icon)
FreeDiskObject(Icon);
}
/* UpdateModeString():
*
* This routine builds the screen mode and screen depth string
* for the user interface.
*/
VOID
UpdateModeString()
{
WORD Len;
if(!GetModeName(DisplayID,DisplayModeBuffer))
strcpy(DisplayModeBuffer,"«Default screen mode»");
Len = strlen(DisplayModeBuffer);
if(Depth)
SPrintf(&DisplayModeBuffer[Len],", %ld colours",1L << Depth);
else
strcpy(&DisplayModeBuffer[Len],", «Maximum depth»");
}
/* SaveOptions(char **argv):
*
* Here we store the current options within the program icon.
*/
VOID
SaveOptions(char **argv)
{
STATIC STRPTR KnownTypes[] =
{
"CX_PRIORITY",
"CX_POPKEY",
"CX_POPUP",
"BLANKSCREEN",
"SAVESCREEN",
"FRACTAL",
"COLOUR",
"DISPLAYMODE",
"DEPTH",
"SCREENTIMEOUT",
"PATTERNTIMEOUT",
"MAXRECURSION",
"MAXDOTS"
};
struct WBStartup *Startup = (struct WBStartup *)argv;
BPTR OldDir;
struct DiskObject *Icon;
OldDir = CurrentDir(MainProcess -> pr_HomeDir);
// Get the program icon
if(Icon = GetDiskObject(Startup -> sm_ArgList -> wa_Name))
{
STRPTR *Types,
*NewTypes,
Data;
LONG Count = 0,Known = sizeof(KnownTypes) / sizeof(STRPTR),Len = 0,i;
// Count the number of tooltypes present
if(Types = (STRPTR *)Icon -> do_ToolTypes)
{
while(Types[Count])
Count++;
}
// Count the room required for the tooltypes to add
for(i = 0 ; i < Known ; i++)
Len += strlen(KnownTypes[i]) + 2;
// Add room for the keys
Len += (10) + (256) + (4) + (256) + (256) + (8) + (8) + (40) + (10) + (10) + (10) + (10) + (10);
// All the data will go here
if(NewTypes = (STRPTR *)AllocVec(Len + (Count + 1 + Known) * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR))
{
STRPTR *Tool = NewTypes,String;
UBYTE LocalBuffer[DISPLAYNAMELEN];
Data = (STRPTR)&NewTypes[Count + 1 + Known];
// CX_PRIORITY=[..]
SPrintf(Data,"CX_PRIORITY=%ld",NewBroker . nb_Pri);
*Tool++ = Data;
Data += strlen(Data) + 1;
// CX_POPKEY=[..]
SPrintf(Data,"CX_POPKEY=%s",HotkeyBuffer);
*Tool++ = Data;
Data += strlen(Data) + 1;
// CX_POPUP=[..]
SPrintf(Data,"CX_POPUP=%s",PopUp ? "yes" : "no");
*Tool++ = Data;
Data += strlen(Data) + 1;
// BLANKSCREEN=[..]
SPrintf(Data,"BLANKSCREEN=%s",BlankScreenBuffer);
*Tool++ = Data;
Data += strlen(Data) + 1;
// SAVESCREEN=[..]
SPrintf(Data,"SAVESCREEN=%s",SaveScreenBuffer);
*Tool++ = Data;
Data += strlen(Data) + 1;
// FRACTAL=[..]
switch(FractalType)
{
case FRACTAL_REAL_PLANE:
String = "REALPLANE";
break;
case FRACTAL_COSMIC_FLAME:
String = "COSMICFLAME";
break;
case FRACTAL_RANDOM:
String = "RANDOM";
break;
}
SPrintf(Data,"FRACTAL=%s",String);
*Tool++ = Data;
Data += strlen(Data) + 1;
// COLOUR=[..]
switch(ColourMode)
{
case COLOUR_CYCLE:
String = "CYCLE";
break;
case COLOUR_STATIC:
String = "STATIC";
break;
}
SPrintf(Data,"COLOUR=%s",String);
*Tool++ = Data;
Data += strlen(Data) + 1;
// DISPLAYMODE=[..]
if(GetModeName(DisplayID,LocalBuffer))
{
SPrintf(Data,"DISPLAYMODE=%s",LocalBuffer);
*Tool++ = Data;
Data += strlen(Data) + 1;
}
// DEPTH=[..]
SPrintf(Data,"DEPTH=%ld",Depth);
*Tool++ = Data;
Data += strlen(Data) + 1;
// SCREENTIMEOUT=[..]
SPrintf(Data,"SCREENTIMEOUT=%ld:%02ld",ScreenTimeout / 60,ScreenTimeout % 60);
*Tool++ = Data;
Data += strlen(Data) + 1;
// PATTERNTIMEOUT=[..]
SPrintf(Data,"PATTERNTIMEOUT=%ld:%02ld",PatternTimeout / 60,PatternTimeout % 60);
*Tool++ = Data;
Data += strlen(Data) + 1;
// MAXRECURSION=[..]
SPrintf(Data,"MAXRECURSION=%ld",MaxRecursionLevel);
*Tool++ = Data;
Data += strlen(Data) + 1;
// MAXDOTS=[..]
SPrintf(Data,"MAXDOTS=%ld",MaxFlamePoints * 100);
*Tool++ = Data;
// Now add the remaining old tooltypes,
// unless we already took care of them
if(Types = (STRPTR *)Icon -> do_ToolTypes)
{
BOOL GotIt;
while(*Types)
{
GotIt = FALSE;
for(i = 0 ; i < Known ; i++)
{
if(!Strnicmp(*Types,KnownTypes[i],strlen(KnownTypes[i])))
{
GotIt = TRUE;
break;
}
}
if(!GotIt)
*Tool++ = *Types;
Types++;
}
}
// Install the new tooltypes
Icon -> do_ToolTypes = (char **)NewTypes;
// Write the icon
if(!PutDiskObject(Startup -> sm_ArgList -> wa_Name,Icon))
ReportError(Window,"Error writing icon\n%s",IoErr());
// Clean up
FreeVec(NewTypes);
}
else
ReportError(Window,NULL,ERROR_NO_FREE_STORE);
FreeDiskObject(Icon);
}
else
ReportError(Window,"Error reading icon\n%s",IoErr());
CurrentDir(OldDir);
}
/* main(int argc,char **argv):
*
* That's where all the trouble starts.
*/
void __stdargs
main(int argc,char **argv)
{
ULONG SignalSet;
BOOL Done = FALSE;
// Open everything we need
OpenAll(argc,argv);
// Go into loop waiting for messages
do
{
// Wait for a signal...
SignalSet = SIG_CX | SIG_BREAK | SIG_WAKEUP;
if(Window)
SignalSet |= SIG_WINDOW;
SignalSet = Wait(SignalSet);
// Check the commodities toolkit reply port
if(SignalSet & SIG_CX)
{
CxMsg *Message;
while(Message = (CxMsg *)GetMsg(CxPort))
HandleCxMsg(Message);
}
// ^C tells the program to quit
if(SignalSet & SIG_BREAK)
Done = TRUE;
// ^F tells the program to open its control panel
if(SignalSet & SIG_WAKEUP)
SetupWindow();
// If the control panel is still open,
// check for new messages.
if(Window)
{
if(SignalSet & SIG_WINDOW)
{
struct IntuiMessage *IMsg;
BOOL Hide = FALSE;
ULONG MsgClass;
struct Gadget *MsgGadget;
ULONG LocalID,LocalDepth;
IX Expression;
BOOL NewKeys;
STRPTR String;
LONG Error;
struct IBox Box;
while(IMsg = LT_GetIMsg(Handle))
{
MsgClass = IMsg -> Class;
MsgGadget = (struct Gadget *)IMsg -> IAddress;
LT_ReplyIMsg(IMsg);
switch(MsgClass)
{
case IDCMP_CLOSEWINDOW:
Hide = TRUE;
break;
case IDCMP_GADGETUP:
switch(MsgGadget -> GadgetID)
{
case GAD_QUIT:
Done = TRUE;
break;
// Make sure that the key
// codes are correct
case GAD_BLANKSCREEN:
case GAD_SAVESCREEN:
case GAD_HOTKEY:
if(ParseIX(LT_GetString(Handle,MsgGadget -> GadgetID),&Expression))
{
DisplayBeep(Window -> WScreen);
LT_Activate(Handle,MsgGadget -> GadgetID);
}
break;
case GAD_HIDE:
case GAD_SAVE:
LT_LockWindow(Window);
// Update the Commodities
// interface only if the
// key assignments have
// changed
NewKeys = FALSE;
String = LT_GetString(Handle,GAD_HOTKEY);
if(!ParseIX(String,&Expression))
{
IX OldExpression;
ParseIX(HotkeyBuffer,&OldExpression);
if(memcmp(&Expression,&OldExpression,sizeof(IX)))
{
SpecialQualifier = SubQualifier(HotkeyBuffer,SpecialQualifier);
strcpy(HotkeyBuffer,String);
SpecialQualifier = AddQualifier(HotkeyBuffer,SpecialQualifier);
NewKeys = TRUE;
}
}
String = LT_GetString(Handle,GAD_BLANKSCREEN);
if(!ParseIX(String,&Expression))
{
IX OldExpression;
ParseIX(BlankScreenBuffer,&OldExpression);
if(memcmp(&Expression,&OldExpression,sizeof(IX)))
{
SpecialQualifier = SubQualifier(BlankScreenBuffer,SpecialQualifier);
strcpy(BlankScreenBuffer,String);
SpecialQualifier = AddQualifier(BlankScreenBuffer,SpecialQualifier);
NewKeys = TRUE;
}
}
String = LT_GetString(Handle,GAD_SAVESCREEN);
if(!ParseIX(String,&Expression))
{
IX OldExpression;
ParseIX(SaveScreenBuffer,&OldExpression);
if(memcmp(&Expression,&OldExpression,sizeof(IX)))
{
SpecialQualifier = SubQualifier(SaveScreenBuffer,SpecialQualifier);
strcpy(SaveScreenBuffer,String);
SpecialQualifier = AddQualifier(SaveScreenBuffer,SpecialQualifier);
NewKeys = TRUE;
}
}
LT_UnlockWindow(Window);
if(NewKeys)
{
if(Error = SetupCx())
{
if(Error != ERR_Duplicate)
ReportError(Window,NULL,Error);
CloseAll(RETURN_FAIL);
}
}
if(MsgGadget -> GadgetID == GAD_HIDE)
Hide = TRUE;
else
SaveOptions(argv);
break;
}
break;
// Pick a new display mode
case IDCMP_IDCMPUPDATE:
if(DisplayID == INVALID_ID)
LocalID = GetVPModeID(&Window -> WScreen -> ViewPort);
else
LocalID = DisplayID;
if(Depth)
LocalDepth = Depth;
else
{
struct DimensionInfo DimensionInfo;
if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(DimensionInfo),DTAG_DIMS,LocalID))
LocalDepth = DimensionInfo . MaxDepth;
else
LocalDepth = 2;
}
if(ScreenModeRequest -> sm_UserData && !ResetRequest)
CopyMem(&ScreenModeRequest -> sm_LeftEdge,&Box,sizeof(struct IBox));
else
{
CopyMem(&Window -> LeftEdge,&Box,sizeof(struct IBox));
Box . Top += Window -> BorderTop;
Box . Height -= Window -> BorderTop;
}
if(AslRequestTags(ScreenModeRequest,
ASLSM_Window, Window,
ASLSM_SleepWindow, TRUE,
ASLSM_InitialDisplayID, LocalID,
ASLSM_InitialDisplayDepth, LocalDepth,
ASLSM_UserData, TRUE,
ASLSM_InitialLeftEdge, Box . Left,
ASLSM_InitialTopEdge, Box . Top,
ASLSM_InitialWidth, Box . Width,
ASLSM_InitialHeight, Box . Height,
TAG_DONE))
{
ResetRequest = FALSE;
DisplayID = ScreenModeRequest -> sm_DisplayID;
Depth = ScreenModeRequest -> sm_DisplayDepth;
UpdateModeString();
LT_SetAttributes(Handle,GAD_MODE,
GTTX_Text, DisplayModeBuffer,
TAG_DONE);
}
else
ResetRequest = TRUE;
break;
}
}
if(Hide)
ShutdownWindow();
}
}
}
while(!Done);
CloseAll(RETURN_OK);
}